#include "Scene.h"
#include "Node.h"
#include "Editor.h"
#include "HierarchyTreeModel.h"
#include <QtGui>
#include "SceneView.h"
#include <cmath>

Scene::Scene(void)
: m_pOperatingNode(0), isMovingView(false), isScalingView(false)
{
	root = new Node();
	root->name = "root";
	Node::scene = this;

	model = new HierarchyTreeModel(root);
}

Scene::Scene(Node* root)
: m_pOperatingNode(0), isMovingView(false), isScalingView(false)
{
	this->root = root;
	Node::scene = this;

	model = new HierarchyTreeModel(root);
}

Scene::~Scene(void)
{
	delete root;
}



Node* Scene::createEmpty() {
	return new Node();
}

Node* Scene::createSprite() {
	return new SpriteNode();
}
Node* Scene::createLayer() {
	return new LayerNode();
}

void Scene::freeNode(Node* node) {
	delete node;
}

void Scene::addNode(Node* node) {
	model->addNode(node);
	
	updateView();
}

void Scene::removeNode(Node* node) {
	model->removeNode(node);
	
	updateView();
}

void Scene::setCurrentNode(Node* node) {
	model->setCurrentNode(node);
}

void Scene::updateNode(Node* node) {
	model->updateNode(node);
}

void Scene::keyPressEvent(QKeyEvent* event) {
	if (event->key() == Qt::Key_Delete) {
		QList<Node*> selection;
		findSelection(root, selection);
		if (!selection.empty()) {
			Editor::ins().invokeNewCommand(new RemoveNodeCommand(selection));
		}
	}
}

void Scene::keyReleaseEvent(QKeyEvent* event) {
}

void Scene::beginMove(QMouseEvent* event) {	
	QPointF pos = event->pos();
	Node* node = hitNode(pos);
	if (node != 0) {
		Editor::ins().selectNode(node);
		m_pOperatingNode = node;
		m_OperatingOffX = pos.x() - node->x();
		m_OperatingOffY = pos.y() - node->y();
		moveCommand = new MoveNodeCommand(node, node->x(), node->y());
	}
}

void Scene::doMove(QMouseEvent* event) {
	QPointF pos = event->pos();
	QPointF worldPos = pos * root->worldToNodeTransform();
	Editor::ins().getUI().statusBar->showMessage(QString().sprintf("x: %.2f\t\ty: %.2f", worldPos.x(), worldPos.y()));
	if (m_pOperatingNode != 0) {
		m_pOperatingNode->setPos(pos.x() - m_OperatingOffX, pos.y() - m_OperatingOffY);
	}
}

void Scene::endMove(QMouseEvent* event) {
	if (m_pOperatingNode) {
		moveCommand->tx = m_pOperatingNode->x();
		moveCommand->ty = m_pOperatingNode->y();
		Editor::ins().pushCommand(moveCommand);
		Editor::ins().updateCurrentNodeInfo();
	}
	m_pOperatingNode = 0;
}

void Scene::beginMoveView(QMouseEvent* event) {
	isMovingView = true;
	QPointF pos = event->pos();
	m_OperatingOffX = pos.x() - root->x();
	m_OperatingOffY = pos.y() - root->y();
}

void Scene::doMoveView(QMouseEvent* event) {
	QPointF pos = event->pos();
	root->setPos(pos.x() - m_OperatingOffX, pos.y() - m_OperatingOffY);
}

void Scene::endMoveView(QMouseEvent* event) {
	isMovingView = false;
}

void Scene::beginScaleView(QMouseEvent* event) {
	isScalingView = true;
	m_OperatingOffY = event->pos().y();
}

void Scene::doScaleView(QMouseEvent *event) {
	float factor = pow(1.05f, (float)(event->pos().y() - m_OperatingOffY));
	root->setScaleX(root->scaleX() * factor);
	root->setScaleY(root->scaleY() * factor);
	m_OperatingOffY = event->pos().y();
}

void Scene::endScaleView(QMouseEvent *event) {
	isScalingView = false;
}

bool Scene::isHandlingAction() const {
	return isMovingView || isScalingView || m_pOperatingNode != 0;
}

void Scene::updateView() {
	((SceneView*)Editor::ins().centralWidget())->viewport()->update();
}

void Scene::paint(QPainter& painter) {
	paintNode(painter, root);
}

void Scene::paintNode(QPainter& painter, Node* node) {
	QTransform t = painter.transform();
	painter.setTransform(node->transform(), true);

	node->paint(painter);
	if (node->selected()) {
		painter.drawRect(node->boundingRect());
	}
	foreach(Node* ch, node->children) {
		paintNode(painter, ch);
	}
	painter.setTransform(t, false);
}

Node* Scene::hitNode(QPointF& point, Node* node) {
	if (node == 0) node = root;
	QListIterator<Node*> it(node->children);
	it.toBack();
	while(it.hasPrevious()) {
		Node* ch = it.previous();
		Node* node = hitNode(point, ch);
		if (node != 0) return node;
	}
	if (node->contains(point))
		return node;
	return 0;
}

void Scene::notifyNodeChange(Node *node) {
	((SceneView*)Editor::ins().centralWidget())->viewport()->update();
}

void Scene::clearNodeSelection(Node* node) {
	node->m_Selected = false;
	foreach(Node* ch, node->children) {
		clearNodeSelection(ch);
	}
}
void Scene::clearSelection() {
	clearNodeSelection(root);
}

void Scene::findSelection(Node* node, QList<Node*>& out) {
	if (node->m_Selected) out.append(node);
	foreach(Node* ch, node->children) {
		findSelection(ch, out);
	}
}
